
// 代码题四
// 手写实现promise源码

const { reject } = require("lodash")

const PENDING = 'pending' //等待
const FULFILLED = 'fulfilled' //成功
const REJECTED = 'rejected' //失败

class MyPromise{
    // 在构造函数constructor中创建执行器executor，executor是立即执行的，里面传入两个参数，分别代表两个状态
    constructor (executor){
        try{
            executor(this.resolve,this.reject)
        }catch(e){
            this.reject(e)
        }
        
    }
    // 状态：是每个promise独有的，所以用属性表示
    status = PENDING
    // 成功之后的值
    value = undefined
    // 失败之后的原因
    reason = undefined

    // 成功回调
    successCallback = []

    // 失败回调
    failCallback = []

    // resolve，reject这两个参数用来更改状态
    // 这里要用箭头函数保证this指向promise对象
    resolve = value =>{
        if(this.status !== PENDING) return
        this.status = FULFILLED
        // 保存成功之后的值
        this.value = value
        // 判断成功回调是否存在 如果存在 调用
        // this.successCallback && this.successCallback(this.value)

        while(this.successCallback.length){
            this.successCallback.shift()()
        }
        
    }
    reject = reason => {
        if(this.status !== PENDING) return
        this.status = REJECTED
        // 保存失败之后的原因
        this.reason = reason
        // 判断失败回调是否存在 如果存在 调用
        // this.failCallback && this.failCallback(this.reason)
        while(this.failCallback.length) this.failCallback.shift()()
    }
    // then接收两个参数，分别是成功的回调和失败的回调
    then(successCallback,failCallback){
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => {throw reason}
        let promise2 = new MyPromise((resolve,reject) => {
            // 判断状态
            if(this.status = FULFILLED){
                setTimeout(() => {
                    try{
                        let x = successCallback(this.value)
                        resolvePromise(promise2,x,resolve,reject)
                    }catch(e){
                        reject(e)
                    }
                }, 0);
                
            }else if(this.status = REJECTED){
                setTimeout(() => {
                    try{
                        let x = failCallback(this.reason)
                        resolvePromise(promise2,x,resolve,reject)
                    }catch(e){
                        reject(e)
                    }
                }, 0);
            }else{
                //等待
                this.successCallback.push(()=>{
                    setTimeout(() => {
                        try{
                            let x = successCallback(this.value)
                            resolvePromise(promise2,x,resolve,reject)
                        }catch(e){
                            reject(e)
                        }
                    }, 0);
                })
                this.failCallback.push(()=>{
                    setTimeout(() => {
                        try{
                            let x = failCallback(this.reason)
                            resolvePromise(promise2,x,resolve,reject)
                        }catch(e){
                            reject(e)
                        }
                    }, 0);
                })
            }
        })
        return promise2
    }
    // promise.all方法是用来解决异步并发问题的，它允许我们用异步代码调用的顺序得到异步代码执行的结果。它的返回值是promise对象，所以可以链式调用then方法。特点：all方法中的所有promise对象的状态都是成功的，all方法的结果就是成功的，如果有一个失败，结果就是失败的。
    static all(array){
        return new MyPromise((resolve,seject)=>{
            let result = []
            let index = 0
            function addData(key,value){
                result[key] = value
                index++
                if(index === arrray.length){
                    resolve(result)
                }
            }
            for(let i=0;i<array.length;i++){
                let current = array[i]
                if(current instanceof MyPromise){
                    //promise对象
                    current.then(value => addData(i,value),reason =>reject(reason))
                }else{
                    //普通值
                    addData(i,arry[i])
                }
            }
        })
    }
    // resolve方法是一个静态方法，它的作用就是把给定的值转化成promise对象
    static resolve(value){
        // value是promise对象，直接返回
        if(value instanceof MyPromise) return value
        // 如果不是promise对象,创建一个promise对象，传递一个执行器。并把创建的promise对象作为resolve方法的返回值返回
        return new MyPromise(resolve => resolve(value))

    }
}

function resolvePromise (promise2,x,resolve,reject){
    if(promise2 === x){
        return
    }
    if(x instanceof MyPromise){
        // promise对象
        // x.then(value => resolve(value),reason => reject(reason))
        x.then(resolve,resolve)
    }else{
        // 普通值
        resolve()
    }
}

module.exports = MyPromise